package cn.flying.cloud.system.resource.service.impl;

import javax.annotation.Resource;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.flying.cloud.base.common.utils.Ft;
import cn.flying.cloud.base.common.vo.PageRequest;
import cn.flying.cloud.base.common.vo.PageResponse;
import cn.flying.cloud.base.common.vo.vue.TreeInfoVO;
import cn.flying.cloud.common.enums.SeqTypeEnum;
import cn.flying.cloud.common.enums.StatusEnum;
import cn.flying.cloud.system.log.service.SysSeqInfoService;
import cn.flying.cloud.system.resource.entity.SysResInfo;
import cn.flying.cloud.system.resource.mapper.SysResInfoMapper;
import cn.flying.cloud.system.resource.service.SysResInfoService;
import cn.flying.cloud.system.role.service.SysRoleResService;
import cn.flying.cloud.system.user.entity.SysUserRole;
import cn.flying.cloud.system.user.service.SysUserRoleService;
import cn.flying.cloud.system.vo.MenuInfoVO;
import cn.flying.cloud.system.vo.ResInfoVO;

/**
 * <p>
 * 资源信息表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2024-04-02 13:07:17
 */
@Service
public class SysResInfoServiceImpl extends ServiceImpl<SysResInfoMapper, SysResInfo> implements SysResInfoService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private SysSeqInfoService sysSeqInfoService;
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private SysRoleResService sysRoleResService;

    /**
     * 分页查询资源信息表数据
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<SysResInfo> getPageList(PageRequest<SysResInfo> request) {
        SysResInfo param = request.getParam();
        LambdaQueryWrapper<SysResInfo> wrapper = getLambdaQueryWrapper(param);
        Page<SysResInfo> page = this.page(new Page<>(request.getPageNum(), request.getPageSize()), wrapper);
        return new PageResponse<>(page.getTotal(), (int) page.getCurrent(), page.getRecords());
    }

    /**
     * 构建查询对象
     *
     * @param param
     * @return
     */
    private LambdaQueryWrapper<SysResInfo> getLambdaQueryWrapper(SysResInfo param) {
        LambdaQueryWrapper<SysResInfo> wrapper = new LambdaQueryWrapper<>();
        if (param != null) {
            if (Ft.String.isNotBlank(param.getResId())) {
                wrapper.eq(SysResInfo::getResId, param.getResId());
            }
            if (Ft.String.isNotBlank(param.getParentId())) {
                wrapper.eq(SysResInfo::getParentId, param.getParentId());
            }
            if (Ft.String.isNotBlank(param.getTitle())) {
                wrapper.eq(SysResInfo::getTitle, param.getTitle());
            }
            if (Ft.String.isNotBlank(param.getStatus())) {
                wrapper.eq(SysResInfo::getStatus, param.getStatus());
            }
        }
        return wrapper;
    }

    /**
     * 列表查询资源信息表数据
     *
     * @param sysResInfo
     * @return
     */
    @Override
    public List<ResInfoVO> getList(SysResInfo sysResInfo) {
        LambdaQueryWrapper<SysResInfo> wrapper = new LambdaQueryWrapper<>();
//        if (Ft.String.isNotBlank(sysResInfo.getResId())) {
//            wrapper.eq(SysResInfo::getParentId, sysResInfo.getResId());
//        }
        if (Ft.String.isNotBlank(sysResInfo.getStatus())) {
            wrapper.eq(SysResInfo::getStatus, sysResInfo.getStatus());
        }
        List<SysResInfo> list = this.list(wrapper);
        List<ResInfoVO> infoVOS = list.stream().map(resInfo -> {
            ResInfoVO infoVO = new ResInfoVO();
            Ft.BeanCopier.copy(resInfo, infoVO);
            return infoVO;
        }).collect(Collectors.toList());
        String parentId = Ft.String.isNotBlank(sysResInfo.getResId()) ? sysResInfo.getResId() : "root";
        return setResInfoChildren(infoVOS, parentId);
    }

    /**
     * 赋值child
     *
     * @param list
     * @param parentId
     * @return
     */
    private List<ResInfoVO> setResInfoChildren(List<ResInfoVO> list, String parentId) {
        return list.stream()
                // 过滤父节点
                .filter(parent -> parent.getParentId().equals(parentId))
                // 把父节点children递归赋值成为子节点
                .map(child -> {
                    List<ResInfoVO> temp = setResInfoChildren(list, child.getResId());
                    if (!CollectionUtils.isEmpty(temp)) {
                        child.setChildren(temp);
                    }
                    return child;
                }).collect(Collectors.toList());
    }


    /**
     * 查询资源信息表详情数据
     *
     * @param sysResInfo
     * @return
     */
    @Override
    public SysResInfo getOneObj(SysResInfo sysResInfo) {
        LambdaQueryWrapper<SysResInfo> wrapper = new LambdaQueryWrapper<>();
        return this.getOne(wrapper);
    }

    /**
     * 获取用户菜单信息
     *
     * @param userId
     * @return
     */
    @Override
    public List<MenuInfoVO> getMenuInfos(String userId, String tenantId) {
        List<SysResInfo> list;
        // 内置， 10000 为系统账户用户
        if ("10000".equals(userId)) {
            LambdaQueryWrapper<SysResInfo> wrapper = new LambdaQueryWrapper<>();
            // 加载左侧导航菜单要排除按钮
            wrapper.ne(SysResInfo::getType, "B");
            wrapper.eq(SysResInfo::getStatus, StatusEnum.STATUS_Y.getCode());
            list = this.list(wrapper);
        } else {
            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(userId);
            List<SysUserRole> userRoles = sysUserRoleService.getList(userRole);
            if (CollectionUtils.isEmpty(userRoles)) {
                return new ArrayList<>();
            }

            // 如果角色包含了系统账户、系统管理员（10000为系统账户、10001为系统管理员），则直接查询全部
            Optional<String> optional = userRoles.stream().map(SysUserRole::getRoleId).filter(roleId -> "10000".equals(roleId) || "10001".equals(roleId)).findAny();
            if (optional.isPresent()) {
                LambdaQueryWrapper<SysResInfo> wrapper = new LambdaQueryWrapper<>();
                // 加载左侧导航菜单要排除按钮
                wrapper.ne(SysResInfo::getType, "B");
                wrapper.eq(SysResInfo::getStatus, StatusEnum.STATUS_Y.getCode());
                list = this.list(wrapper);
            } else {
                List<SysResInfo> infos = this.getBaseMapper().getMenuInfosByUserId(userId, tenantId);
                if (CollectionUtils.isEmpty(infos)) {
                    return new ArrayList<>();
                }
                list = infos.stream().filter(resInfo -> !"B".equals(resInfo.getType())).collect(Collectors.toList());

//                Set<SysResInfo> set = new HashSet<>();
//                LambdaQueryWrapper<SysResInfo> wrapper = new LambdaQueryWrapper<>();
//                // 加载左侧导航菜单要排除按钮
//                wrapper.ne(SysResInfo::getType, "B");
//                List<SysResInfo> allRes = this.list(wrapper);
//                Map<String, SysResInfo> map = new HashMap<>();
//                for (SysResInfo info : allRes) {
//                    map.put(info.getResId(), info);
//                }
//                // 递归查询父级菜单
//                for (SysResInfo info : list) {
//                    recursiveFind(info.getResId(), map, set);
//                }
//                list.addAll(set);
            }
        }

        Map<String, List<SysResInfo>> listMap = list.stream().collect(Collectors.groupingBy(SysResInfo::getParentId));
        List<SysResInfo> resInfos = listMap.get("root");
        List<MenuInfoVO> menuInfos = setMenuInfoChildren(resInfos, listMap);
        return menuInfos.get(0).getChildren();
    }

    /**
     * 递归查找父级菜单
     *
     * @param resId  当前查找的资源ID
     * @param map    资源数据
     * @param result 结果集合
     */
    private static void recursiveFind(String resId, Map<String, SysResInfo> map, Set<SysResInfo> result) {
        SysResInfo info = map.get(resId);
        if (info == null) {
            return;
        }

        String parentId = info.getParentId();
        if (parentId != null && map.containsKey(parentId)) {
            SysResInfo parent = map.get(parentId);
            result.add(parent);
            recursiveFind(parentId, map, result);
        }
    }

    /**
     * 设置子菜单
     *
     * @param list
     * @param listMap
     * @return
     */
    private List<MenuInfoVO> setMenuInfoChildren(List<SysResInfo> list, Map<String, List<SysResInfo>> listMap) {
        List<MenuInfoVO> menuInfos = new ArrayList<>();
        list.stream().sorted(Comparator.comparing(SysResInfo::getSeq)).collect(Collectors.toList()).forEach(sysResInfo -> {
            MenuInfoVO menuInfoVo = new MenuInfoVO();
            menuInfoVo.setName(sysResInfo.getName());
            menuInfoVo.setPath(sysResInfo.getPath());
            menuInfoVo.setComponent(sysResInfo.getComponent());
            menuInfoVo.setHidden(!StatusEnum.STATUS_Y.getCode().equals(sysResInfo.getIsShow()));
            menuInfoVo.setRedirect("noRedirect");
            MenuInfoVO.Meta meta = new MenuInfoVO.Meta();
            meta.setTitle(sysResInfo.getTitle());
            meta.setIcon(sysResInfo.getIcon());
            meta.setNoCache(false);
            menuInfoVo.setMeta(meta);

            List<SysResInfo> children = listMap.get(sysResInfo.getResId());
            if (CollectionUtils.isNotEmpty(children)) {
                menuInfoVo.setChildren(setMenuInfoChildren(children, listMap));
                menuInfoVo.setAlwaysShow(true);
            } else {
                menuInfoVo.setChildren(new ArrayList<>());
                menuInfoVo.setAlwaysShow(false);
            }
            menuInfos.add(menuInfoVo);
        });
        return menuInfos;
    }

    /**
     * 获取所有的资源树
     *
     * @return
     */
    @Override
    public List<TreeInfoVO> getAllResList(String type) {
        LambdaQueryWrapper<SysResInfo> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(type)) {
            wrapper.ne(SysResInfo::getType, type);
        }
        List<SysResInfo> resInfos = this.list(wrapper);
        Map<String, List<SysResInfo>> listMap = resInfos.stream().collect(Collectors.groupingBy(SysResInfo::getParentId));
        return setTreeInfoChildren(listMap.get("root"), listMap);
    }

    /**
     * 迭代设置children
     *
     * @param list
     * @param listMap
     * @return
     */
    private List<TreeInfoVO> setTreeInfoChildren(List<SysResInfo> list, Map<String, List<SysResInfo>> listMap) {
        List<TreeInfoVO> infoVOs = new ArrayList<>();
        list.forEach(sysResInfo -> {
            TreeInfoVO infoVO = new TreeInfoVO();
            infoVO.setId(sysResInfo.getResId());
            infoVO.setLabel(sysResInfo.getTitle());

            List<SysResInfo> children = listMap.get(sysResInfo.getResId());
            if (CollectionUtils.isNotEmpty(children)) {
                infoVO.setChildren(setTreeInfoChildren(children, listMap));
            } else {
                infoVO.setChildren(new ArrayList<>());
            }
            infoVOs.add(infoVO);
        });
        return infoVOs;
    }

    /**
     * 新增资源信息表数据
     *
     * @param sysResInfo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean createObj(SysResInfo sysResInfo) {
        sysResInfo.setResId(sysSeqInfoService.getNextSeq(SeqTypeEnum.MENU.name()));
        sysResInfo.setTenantId(Ft.Local.TenantId());
        if (!"B".equals(sysResInfo.getType()) && Ft.String.isBlank(sysResInfo.getIcon())) {
            sysResInfo.setIcon("app");
        }
        this.save(sysResInfo);

        // D目录 M菜单 B按钮
        if ("M".equals(sysResInfo.getType())) {
            // 类型为菜单，默认添加增删改查按钮
            // 列表查询
            SysResInfo query = new SysResInfo();
            query.setResId(sysSeqInfoService.getNextSeq(SeqTypeEnum.MENU.name()));
            query.setParentId(sysResInfo.getResId());
            query.setName(sysResInfo.getName() + "_list");
            query.setType("B");
            query.setSeq(1);
            query.setTitle(sysResInfo.getTitle() + "列表查询");
            query.setMid(query.getName().replace("_", ":"));
            query.setIsFrame("N");
            query.setStatus("Y");
            query.setIsShow("Y");
            query.setTenantId(Ft.Local.TenantId());
            this.save(query);

            // 新增按钮
            SysResInfo add = new SysResInfo();
            add.setResId(sysSeqInfoService.getNextSeq(SeqTypeEnum.MENU.name()));
            add.setParentId(sysResInfo.getResId());
            add.setName(sysResInfo.getName() + "_add");
            add.setType("B");
            add.setSeq(2);
            add.setTitle(sysResInfo.getTitle() + "新增按钮");
            add.setMid(add.getName().replace("_", ":"));
            add.setIsFrame("N");
            add.setIsShow("Y");
            add.setStatus("Y");
            add.setTenantId(Ft.Local.TenantId());
            this.save(add);

            // 新增按钮
            SysResInfo edit = new SysResInfo();
            edit.setResId(sysSeqInfoService.getNextSeq(SeqTypeEnum.MENU.name()));
            edit.setParentId(sysResInfo.getResId());
            edit.setName(sysResInfo.getName() + "_edit");
            edit.setType("B");
            edit.setSeq(3);
            edit.setTitle(sysResInfo.getTitle() + "编辑按钮");
            edit.setMid(edit.getName().replace("_", ":"));
            edit.setIsShow("Y");
            edit.setIsFrame("N");
            edit.setStatus("Y");
            edit.setTenantId(Ft.Local.TenantId());
            this.save(edit);

            // 删除按钮
            SysResInfo del = new SysResInfo();
            del.setResId(sysSeqInfoService.getNextSeq(SeqTypeEnum.MENU.name()));
            del.setParentId(sysResInfo.getResId());
            del.setName(sysResInfo.getName() + "_del");
            del.setType("B");
            del.setSeq(4);
            del.setTitle(sysResInfo.getTitle() + "删除按钮");
            del.setMid(del.getName().replace("_", ":"));
            del.setIsFrame("N");
            del.setIsShow("Y");
            del.setStatus("Y");
            del.setTenantId(Ft.Local.TenantId());
            this.save(del);
        }
        return true;
    }

    /**
     * 更新资源信息表数据
     *
     * @param sysResInfo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateObj(SysResInfo sysResInfo) {
        return this.saveOrUpdate(sysResInfo);
    }

    /**
     * 删除资源信息表数据
     *
     * @param sysResInfo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteObj(SysResInfo sysResInfo) {
        LambdaQueryWrapper<SysResInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysResInfo::getResId, sysResInfo.getResId());
        return this.remove(wrapper);
    }

    /**
     * 根据Id删除
     *
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteById(Serializable id) {
        return this.removeById(id);
    }

    /**
     * 根据用户Id查询拥有的权限资源
     *
     * @param userId
     * @return
     */
    @Override
    public List<SysResInfo> getResInfosByUserId(String userId, String tenantId) {
        // 内置， 10000 为系统账户
        if ("10000".equals(userId)) {
            return this.list();
        }
        SysUserRole userRole = new SysUserRole();
        userRole.setUserId(userId);
        List<SysUserRole> userRoles = sysUserRoleService.getList(userRole);
        if (CollectionUtils.isNotEmpty(userRoles)) {
            // 如果角色包含了系统账户、系统管理员（10000为系统账户、10001为系统管理员），则直接查询全部
            Optional<String> optional = userRoles.stream().map(SysUserRole::getRoleId).filter(roleId -> "10000".equals(roleId) || "10001".equals(roleId)).findAny();
            if (optional.isPresent()) {
                return this.list();
            }
        }
        return this.getBaseMapper().getResInfosByUserId(userId, tenantId);
    }
}
